`timescale 1ns / 1ps

/*
# * Copyright {c} 2020-2021, SERI Development Team
# *
# * SPDX-License-Identifier: Apache-2.0
# *
# * Change Logs:
# * Date         Author          Notes
# * 2022-05-22   Lyons           first version
# */

module tb (
    );

localparam CLK_CYCLE_NS         = 32'd1_000;


localparam INT_WIDTH            = 32;
localparam FLOAT_WIDTH          = 64;

localparam DOUBLE_WIDTH         = 64;
localparam SINGLE_WIDTH         = 32;

localparam FLOAT_FMT_SINGLE     = 1'b1;
localparam FLOAT_FMT_DOUBLE     = 1'b0;

localparam SEL_UNIT_FALU        = 3'b001;
localparam SEL_UNIT_FMAU        = 3'b010;
localparam SEL_UNIT_FDSU        = 3'b100;

localparam SEL_FUNC_NULL        = 10'b1111111_111;

localparam SEL_FUNC_FADD        = 10'b0000000_000;
localparam SEL_FUNC_FSUB        = 10'b1000000_000;


reg                             sys_clk;
reg                             sys_rst_n;

reg  [FLOAT_WIDTH-1:0]          src0_i;
reg  [FLOAT_WIDTH-1:0]          src1_i;
reg  [INT_WIDTH-1:0]            srci_i;

reg                             single_i;

reg  [2:0]                      sel_unit_i;
reg  [9:0]                      sel_func_i;

wire [DOUBLE_WIDTH-1:0]         frst_d_o;
wire [SINGLE_WIDTH-1:0]         frst_s_o = frst_d_o[SINGLE_WIDTH-1:0];
wire                            frst_vld_o;

wire [INT_WIDTH-1:0]            irst_o;
wire                            irst_vld_o;

pa_fpu_top u_pa_fpu_top (
    .clk_i                      (sys_clk),
    .rst_n_i                    (sys_rst_n),

    .src0_i                     (src0_i),
    .src1_i                     (src1_i),
    .srci_i                     (srci_i),

    .single_i                   ( single_i),
    .double_i                   (~single_i),

    .sel_unit_i                 (sel_unit_i),
    .sel_func_i                 (sel_func_i),

    .rm_i                       (3'b000),

    .fresult_o                  (frst_d_o),
    .fresult_single_o           (),
    .fresult_double_o           (),
    .fresult_vld_o              (frst_vld_o),

    .iresult_o                  (irst_o),
    .iresult_vld_o              (irst_vld_o)
);

initial begin
    sys_clk = 1;
    sys_rst_n = 1;

    sel_unit_i[2:0] = 3'bx;
    sel_func_i[9:0] = 10'bx;

    src0_i[FLOAT_WIDTH-1:0] = 64'bx;
    src1_i[FLOAT_WIDTH-1:0] = 64'bx;
    srci_i[INT_WIDTH-1:0]   = 32'bx;
end

`ifdef ANNOTATE_SDF
initial begin
	$sdf_annotate("../syn/output/u_pa_fpu_top.sdf", u_pa_fpu_top);
end
`endif

initial begin
`ifdef DUMP_FSDB
	$fsdbDumpfile("wave.fsdb");
    $fsdbDumpvars;
`endif
`ifdef DUMP_VPD
	$vcdplusfile("wave.vpd");
	$vcdpluson(0, tb);
`endif
`ifdef DUMP_VCD
    $dumpfile("wave.vcd");
    $dumpvars(0, tb);
`endif
end

integer                         fp;
integer							frslt;
integer                         num;
integer                         op;
real                            src0;
real                            src1;
integer                         cycles;

real							fa;
real							fb;
real							fout;
real							ftbout;

always begin
    sys_rst_n = 0; @ (posedge sys_clk);
    sys_rst_n = 1; @ (posedge sys_clk);

    fp = $fopen("../../tb/tdata.data", "r");
    $display("");

    frslt = $fscanf(fp, "%d\n", num);

    repeat (num) begin
	    frslt = $fscanf(fp, "%c %f %f\n", op, src0, src1);
	    
	    case (op)
		"+" : begin
		    sel_unit_i = SEL_UNIT_FALU;
		    sel_func_i = SEL_FUNC_FADD;
		    cycles = 4;
		end
		"-" : begin
		    sel_unit_i = SEL_UNIT_FALU;
		    sel_func_i = SEL_FUNC_FSUB;
		    cycles = 4;
		end
	    endcase

	    single_i = FLOAT_FMT_DOUBLE;

	    src0_i[FLOAT_WIDTH-1:0] = $realtobits(src0);
	    src1_i[FLOAT_WIDTH-1:0] = $realtobits(src1);

	    repeat (cycles) begin
		    @ (posedge sys_clk);
	    end

		fa = $bitstoreal(src0_i);
		fb = $bitstoreal(src1_i);
		fout = $bitstoreal(frst_d_o);
		ftbout = fa - fb;

	    $display("%14.7f %c %14.7f = %14.7f (%14.7f, %f)", fa, op, fb, fout, ftbout, $abs(ftbout-fout));
	end

	$fclose(fp);
    $display("");
    
    src0_i[FLOAT_WIDTH-1:0] = 64'bx; //indicate the end edge
    @ (posedge sys_clk) $finish();
end

always #(CLK_CYCLE_NS/2) sys_clk = ~sys_clk;

endmodule
